home *** CD-ROM | disk | FTP | other *** search
- { TPH unit for the Interrupt List -> .TPH compiler. }
- { The software included, data formats and basic algorithms are }
- { copyright (C) 1996 by Slava Gostrenko. All rights reserved. }
-
- {$X+}
- unit
- TPH;
-
- interface
-
- uses
- Objects;
-
- const
- HexChars = ['0'..'9', 'A'..'F', 'a'..'f'];
-
- TPFileStamp = 'TURBO PASCAL HELP FILE.'#0
- + #$1A
- + '$*$* &&&&$*$'#0
- + #$34#02;
- FileStamp : array [0 .. Length (TPFileStamp) - 1] of Char = TPFileStamp;
-
- Of_CaseSense = $0004;
-
- CT_Nibble = 2;
-
- NC_RawChar = $F;
- NC_RepChar = $E;
-
- type
- TRecType =
- (RT_FileHeader,
- RT_Context,
- RT_Text,
- RT_Keyword,
- RT_Index,
- RT_Compression,
- RT_ScreenTags);
-
- TRecHdr = record
- RecType: TRecType;
- RecLength: Word;
- end;
-
- TPFileHdrRec = record
- Options: Word;
- MainIndexScreen: Word;
- MaxScreenSize: Word;
- Height: Byte;
- Width: Byte;
- LeftMargin: Byte;
- end;
-
- TPCompRec = record
- CompType: Byte;
- CharTable: array [0..13] of Char;
- end;
-
- TFileStart = record
- FileHdr_ : TRecHdr;
- FileHdr : TPFileHdrRec;
- CompRec_ : TRecHdr;
- CompRec : TPCompRec;
- end;
-
- PCtxTbl = ^TCtxTbl;
- TCtxTbl = record
- N: Word;
- T: array [0..16382] of Longint;
- end;
-
- TCharCounter = array [Char] of Longint;
-
- PIdxTbl = ^TIdxTbl;
- TIdxTbl = object (TSortedCollection)
- function KeyOf (Item: Pointer): Pointer; virtual;
- function Compare (Key1, Key2: Pointer): Integer; virtual;
- procedure SetCtxs;
- function RealCount: Word;
- procedure Write (var S: TStream);
- procedure AltWrite (var S: TStream; const GlobalAltName: string);
- procedure ReBuild (Level: Integer);
- end;
-
- PTopic = ^TTopic;
- TTopic = object (TStringCollection)
- Size: Longint;
- Keywords: TStringCollection;
- InSwap: Boolean;
- SwapPos: Longint;
-
- constructor Init(ALimit, ADelta: Integer);
-
- procedure Store2Swap (var S: TStream);
- procedure RestoreFromSwap (var S: TStream);
-
- procedure AddString (S: string);
- procedure UpdateCharCounter (var C: TCharCounter);
- procedure Write (var S: TStream; Compression: TPCompRec);
-
- procedure AddKeyword (S: string; StepBack: Integer);
- procedure WriteKeywords (var S: TStream; var IdxTbl: TIdxTbl);
- end;
-
- PIndexEntry = ^TIndexEntry;
- TIndexEntry = object (TObject)
- PS, PS1: PString;
- Ctx: Word;
- Topic: PTopic;
- Indexed: Boolean;
-
- constructor Init (const S, S1: string; ACtx: Word; var ATopic: PTopic; IsIndexed: Boolean);
- procedure Write (var S: TStream; const PrevStr: string);
- procedure AltWrite (var S: TStream);
- destructor Done; virtual;
- end;
-
- PHelpFile = ^THelpFile;
- THelpFile = object (TBufStream)
- FileStart: TFileStart;
- CtxTbl: PCtxTbl;
- IdxTbl: TIdxTbl;
-
- constructor Init(FileName: FNameStr; Mode, Size: Word);
- destructor Done; virtual;
- end;
-
- var
- SwapFile: PBufStream;
-
- implementation
-
- uses
- Upcaser;
-
- procedure CharCounter2CompRec (var C: TCharCounter; var R: TPCompRec);
- var I: Integer;
- J, MC: Char;
- M: Longint;
- begin
- for I := Low (R. CharTable) + 1 to High (R. CharTable) do begin
- M := 0;
- MC := #0;
-
- for J := Low (C) to High (C) do
- if C [J] > M then begin
- MC := J;
- M := C [J];
- end;
-
- R. CharTable [I] := MC;
- C [MC] := 0;
- end;
- end;
-
- { TTopic = object (TStringCollection) }
-
- constructor TTopic. Init(ALimit, ADelta: Integer);
- begin
- inherited Init (ALimit, ADelta);
- Size := 0;
- Keywords. Init (ALimit, ADelta);
-
- InSwap := False;
- SwapPos := -1;
- end;
-
- procedure TTopic. Store2Swap (var S: TStream);
- var I: Integer;
- begin
- if not InSwap then begin
- if SwapPos = -1 then begin
- SwapPos := S. GetSize;
- S. Seek (SwapPos);
- S. Write (Count, 2);
- if Count > 1 then
- for I := 1 to Count - 1 do begin
- S. WriteStr (Items^[I]);
- DisposeStr (Items^[I]);
- Items^[I] := nil;
- end;
- end else
- if Count > 1 then
- for I := 1 to Count - 1 do begin
- DisposeStr (Items^[I]);
- Items^[I] := nil;
- end;
-
- InSwap := True;
- end;
- end;
-
- procedure TTopic. RestoreFromSwap (var S: TStream);
- var I, C: Integer;
- begin
- if InSwap then
- if SwapPos = -1 then begin
- WriteLn ('Swapping error 2');
- Halt (1);
- end else begin
- S. Seek (SwapPos);
- S. Read (C, 2);
- if C > 1 then
- for I := 1 to C - 1 do
- Items^[I] := S. ReadStr;
- InSwap := False;
- end;
- end;
-
- procedure TTopic. AddString (S: string);
- var I, J: Integer;
- begin
- AtInsert (Count, NewStr (S));
-
- if Length (S) < 77 then begin
- Inc (Size, Length (S) + 1);
- end else begin
- I := 77;
-
- while (I > Length (S) - 75) and (S [I] <> ' ') do
- Dec (I);
-
- Inc (Size, I);
-
- J := I - 1 - (Length (S) - I + 1);
- if J < 0 then
- J := 0;
-
- Inc (Size, J + Length (S) - I + 1 + 1);
- end;
-
- if Size > 65535 then
- WriteLn ('error 1');
- end;
-
- procedure TTopic. UpdateCharCounter (var C: TCharCounter);
- procedure DoOneString (PS: PString); far;
- var I: Integer;
- begin
- if PS <> nil then
- for I := 1 to Length (PS^) do
- Inc (C [PS^ [I]]);
- end;
- begin
- RestoreFromSwap (SwapFile^);
- ForEach (@DoOneString);
- Store2Swap (SwapFile^);
- end;
-
- procedure TTopic. Write (var S: TStream; Compression: TPCompRec);
- var
- Buf: Byte;
- Nibble: Integer;
-
- procedure WriteNibble (X: Byte);
- begin
- if Nibble = 0 then begin
- Buf := X;
- Nibble := 1;
- end else begin
- Buf := Buf + X shl 4;
- S. Write (Buf, 1);
- Nibble := 0;
- end;
- end;
-
- procedure WriteChar (C: Char);
- var I: Integer;
- begin
- I := Pos (C, Compression. CharTable);
- if I > 0 then
- WriteNibble (I - 1)
- else begin
- WriteNibble (NC_RawChar);
- WriteNibble (Ord (C) and $F);
- WriteNibble (Ord (C) shr 4);
- end;
- end;
-
- procedure WriteOneString (PS: PString); far;
- procedure DoWrite (const S: string);
- var I, J: Integer;
- begin
- for I := 1 to Length (S) do begin
- J := I + 1;
- while (J <= Length (S)) and (S [J] = S [I]) do
- Inc (J);
- if ((Pos (S [I], Compression. CharTable) = 0) and (J - I > 1))
- or (J - I > 2) then begin
- WriteNibble (NC_RepChar);
- if J - I > 17 then
- J := I + 17;
- WriteNibble (J - I - 2);
- WriteChar (S [I]);
- I := J - 1;
- end else
- WriteChar (S [I]);
- end;
-
- WriteNibble (0);
- end;
- var I, J, KeyCnt: Integer;
- Spcs: string;
- begin
- if PS <> nil then
- if Length (PS^) < 77 then
- DoWrite (PS^)
- else begin
- KeyCnt := 0;
- for I := 1 to 76 do
- if PS^ [I] = #2 then
- Inc (KeyCnt);
- I := 77;
-
- while Odd (KeyCnt)
- or ((I > Length (PS^) - 75)
- and (not (PS^ [I] in [' ']))
- and (not (PS^ [I - 1] in [','])))
- do begin
- Dec (I);
- if PS^ [I] = #2 then
- Dec (KeyCnt);
- end;
-
- DoWrite (Copy (PS^, 1, I - 1));
-
- J := I - 1 - (Length (PS^) - I + 1);
- if J > 0 then begin
- Spcs [0] := Chr (J);
- FillChar (Spcs [1], Ord (Spcs [0]), ' ');
- end else
- Spcs := '';
-
- DoWrite (Spcs + Copy (PS^, I, Length (PS^) - I + 1));
- end
- else
- DoWrite ('');
- end;
-
- var
- R: TRecHdr;
- TextRecStart,
- TextRecEnd: Longint;
-
- begin
- RestoreFromSwap (SwapFile^);
-
- TextRecStart := S. GetPos;
- R. RecType := RT_Text;
- R. RecLength := 0;
- S. Write (R, SizeOf (R));
-
- Nibble := 0;
- ForEach (@WriteOneString);
-
- WriteChar (#1);
-
- if Nibble = 1 then
- WriteNibble (0);
-
- TextRecEnd := S. GetPos;
- R. RecLength := TextRecEnd - TextRecStart - SizeOf (R);
- S. Seek (TextRecStart);
- S. Write (R, SizeOf (R));
- S. Seek (TextRecEnd);
-
- Store2Swap (SwapFile^);
- end;
-
- procedure TTopic. AddKeyword (S: string; StepBack: Integer);
- begin
- Keywords. AtInsert (Keywords. Count - StepBack, NewStr (S));
- end;
-
- procedure TTopic. WriteKeywords (var S: TStream; var IdxTbl: TIdxTbl);
- var
- R: TRecHdr;
- TmpW: Word;
- I, J, K, MinL, SaveMinLIdx, MatchLen, DecCnt: Integer;
- TmpS, MatchS, Helper: string;
- MatchFound: Boolean;
- begin
- R. RecType := RT_Keyword;
- R. RecLength := 6 + Keywords. Count * 2;
- S. Write (R, SizeOf (R));
-
- TmpW := 0;
- S. Write (TmpW, SizeOf (TmpW));
- TmpW := 0;
- S. Write (TmpW, SizeOf (TmpW));
-
- TmpW := Keywords. Count;
- S. Write (TmpW, SizeOf (TmpW));
-
- if Keywords. Count > 0 then
- for I := 0 to Keywords. Count - 1 do begin
- TmpS := StUpcase2 (PString (Keywords. At (I))^);
-
- J := Pos ('"', TmpS);
- if J > 0 then begin
- if TmpS [Length (TmpS)] <> '"' then begin
- Helper := '';
- WriteLn ('error in keyword format - ', TmpS)
- end else begin
- Helper := Copy (TmpS, J + 1, Length (TmpS) - J - 1);
- TmpS [0] := Chr (J - 1);
- end;
- end else
- Helper := '';
-
- DecCnt := 0;
-
- MatchFound := False;
- MinL := High (MinL);
-
- repeat
- IdxTbl. Search (@TmpS, J);
- for K := J to IdxTbl. Count - 1 do begin
- MatchS := StUpcase2 (PIndexEntry (IdxTbl. At (K))^.PS^);
- if Copy (MatchS, 1, Length (TmpS))
- <> TmpS then
- Break
- else begin
- if ((Helper = '')
- or (Pos (Helper, StUpcase2 (PString (PIndexEntry (
- IdxTbl. At (K))^. Topic^. At (0))^)) > 0))
- and (Length (MatchS) - Length (TmpS) < MinL)
- then begin
- MinL := Length (MatchS) - Length (TmpS);
- MatchLen := Length (TmpS);
- SaveMinLIdx := K;
- end;
- end;
- end;
-
- if (DecCnt < 2) and (MinL < High (MinL)) then begin
- MatchFound := True;
- J := SaveMinLIdx;
- end;
-
- Dec (TmpS [0]);
- Inc (DecCnt);
- until MatchFound or (Length (TmpS) < 2);
-
- if (Helper <> '') and (MinL < High (MinL)) then
- MinL := 0;
-
- if not MatchFound then begin
- MatchFound := MinL < High (MinL);
- J := SaveMinLIdx;
- end;
-
- if ( ((Helper = '') or (MinL = High (MinL)))
- and (((MatchLen < 4) and (MinL > 0)) or (MinL > 1))
- )
- and (TmpS [1] in HexChars) and (TmpS [2] in HexChars) then begin
- TmpS := 'INT ' + TmpS [1] + TmpS [2];
- if not IdxTbl. Search (@TmpS, J) then begin
- WriteLn ('error searching for - ', TmpS);
- end else begin
- MinL := 0;
- MatchFound := True;
- end;
- end;
-
- if ( ((Helper = '') or (MinL = High (MinL)))
- and (((MatchLen < 5) and (MinL > 0)) or (MinL > 1))
- )
- and (TmpS [1] = 'P')
- and (TmpS [2] in HexChars + ['x', 'X']) and (TmpS [3] in HexChars + ['x', 'X'])
- and (TmpS [4] in HexChars + ['x', 'X']) and (TmpS [5] in HexChars + ['x', 'X']) then begin
- TmpS := 'PORTS';
- if not IdxTbl. Search (@TmpS, J) then begin
- WriteLn ('error searching for - ', TmpS);
- end else begin
- MinL := 0;
- MatchFound := True;
- end;
- end;
-
- TmpW := PIndexEntry (IdxTbl. At (J))^.Ctx;
-
- if not MatchFound then begin
- WriteLn (PString (At (0))^);
- WriteLn ('error searching for - ', PString (Keywords. At (I))^);
- WriteLn ('found match - ', PIndexEntry (IdxTbl. At (J))^.PS^);
- TmpW := 1;
- end else
- if MinL > 1 then begin
- WriteLn (PString (At (0))^);
- WriteLn ('approximate match to - ', PString (Keywords. At (I))^);
- WriteLn ('is - ', PIndexEntry (IdxTbl. At (J))^.PS^);
- TmpW := 1;
- end;
-
- S. Write (TmpW, SizeOf (TmpW));
- end;
- end;
-
- { TIndexEntry = object (TObject) }
-
- constructor TIndexEntry. Init (const S, S1: string; ACtx: Word; var ATopic: PTopic; IsIndexed: Boolean);
- begin
- inherited Init;
- PS := NewStr (S);
- PS1 := NewStr (S1);
- Ctx := ACtx;
-
- Topic := ATopic;
- ATopic := nil;
- Topic^.Store2Swap (SwapFile^);
-
- Indexed := IsIndexed;
- end;
-
- procedure TIndexEntry. Write (var S: TStream; const PrevStr: string);
- var
- RptChars: Integer;
- LengthCode: Byte;
- begin
- if Length (PS^) > 31 then
- WriteLn ('error 2');
-
- RptChars := 0;
- while (RptChars < Length (PrevStr))
- and (PS^ [RptChars + 1] = PrevStr [RptChars + 1]) do
- Inc (RptChars);
-
- if Length (PS^) = RptChars then
- WriteLn ('error - duplicate index entry!');
-
- if RptChars > 7 then
- RptChars := 7;
-
- LengthCode := (Length (PS^) - RptChars)
- + (RptChars) shl 5;
-
- S. Write (LengthCode, SizeOf (LengthCode));
- S. Write (PS^ [RptChars + 1], Length (PS^) - RptChars);
- S. Write (Ctx, SizeOf (Ctx));
- end;
-
- procedure TIndexEntry. AltWrite (var S: TStream);
- var B: Byte;
- begin
- if Length (PS1^) > 36 then
- WriteLn ('error 2A');
-
- S. Write (Ctx, SizeOf (Ctx));
- S. Write (PS1^, Length (PS1^) + 1);
- B := 0;
- S. Write (B, SizeOf (B));
- end;
-
- destructor TIndexEntry. Done;
- begin
- DisposeStr (PS1);
- DisposeStr (PS);
- inherited Done;
- end;
-
- { TIdxTbl = object (TSortedCollection) }
-
- function TIdxTbl. KeyOf (Item: Pointer): Pointer;
- begin
- KeyOf := PIndexEntry (Item)^. PS;
- end;
-
- function TIdxTbl. Compare (Key1, Key2: Pointer): Integer;
- begin
- if (Key1 = nil) or (StUpcase2 (PString (Key1)^) < StUpcase2 (PString (Key2)^)) then
- Compare := -1
- else
- if (Key2 <> nil) and (StUpcase2 (PString (Key1)^) = StUpcase2 (PString (Key2)^)) then
- Compare := 0
- else
- Compare := 1;
- end;
-
- procedure TIdxTbl. SetCtxs;
- var I: Integer;
- begin
- for I := 0 to Count - 1 do
- PIndexEntry (At (I))^. Ctx := I + 1;
- end;
-
- function TIdxTbl. RealCount: Word;
- var Cnt: Word;
- procedure AddOne (var X: TIndexEntry); far;
- begin
- if (X. PS <> nil)
- and (X. PS^ <> '')
- and X. Indexed then
- Inc (Cnt);
- end;
- begin
- Cnt := 0;
- ForEach (@AddOne);
- RealCount := Cnt;
- end;
-
- procedure TIdxTbl. Write (var S: TStream);
- var PrevStr: string;
- procedure WriteOne (var X: TIndexEntry); far;
- begin
- if (X. PS <> nil)
- and (X. PS^ <> '')
- and X. Indexed then begin
- X. Write (S, PrevStr);
- PrevStr := X. PS^;
- end;
- end;
- begin
- PrevStr := '';
- ForEach (@WriteOne);
- end;
-
- procedure TIdxTbl. AltWrite (var S: TStream; const GlobalAltName: string);
- procedure WriteOne (var X: TIndexEntry); far;
- begin
- if (X. PS1 <> nil)
- and (X. PS1^ <> '')
- and X. Indexed then
- X. AltWrite (S);
- end;
- var
- TmpW: Word;
- TmpS: string;
- begin
- TmpW := $FFFF;
- S. Write (TmpW, SizeOf (TmpW));
-
- TmpS := GlobalAltName;
- TmpS [Length (GlobalAltName) + 1] := #0;
- S. Write (TmpS, Length (GlobalAltName) + 2);
-
- ForEach (@WriteOne);
- end;
-
- procedure TIdxTbl. ReBuild (Level: Integer);
- var PrevStr: string;
- procedure ReBuildOne (var X: TIndexEntry); far;
- var CurStr: string;
- I: Integer;
- begin
- if (X. PS <> nil)
- and (X. PS^ <> '')
- and X.Indexed then begin
- if Length (X. PS^) > Level then begin
- CurStr := Copy (X. PS^, 1, Level);
-
- for I := Length (CurStr) downto 2 do
- if CurStr [I] = ' ' then begin
- CurStr [0] := Chr (I - 1);
- Break;
- end;
-
- DisposeStr (X. PS);
- X. PS := NewStr (CurStr);
- end;
-
- PrevStr := X. PS^;
- end;
- end;
- begin
- PrevStr := '';
- ForEach (@ReBuildOne);
- end;
-
- { THelpFile = object (TBufStream) }
-
- constructor THelpFile.Init(FileName: FNameStr; Mode, Size: Word);
- begin
- inherited Init (FileName, Mode, Size);
- if Mode = stCreate then begin
- Write (FileStamp, SizeOf (FileStamp));
-
- with FileStart do begin
- with FileHdr_ do begin
- RecType := RT_FileHeader;
- RecLength := SizeOf (FileHdr);
- end;
- with FileHdr do begin
- Options := 0;
- MainIndexScreen := 02;
- MaxScreenSize := High (MaxScreenSize) and (-256);
- Height := 24;
- Width := 80;
- LeftMargin := 0;
- end;
-
- with CompRec_ do begin
- RecType := RT_Compression;
- RecLength := SizeOf (CompRec);
- end;
- with CompRec do begin
- CompType := CT_Nibble;
- FillChar (CharTable, SizeOf (CharTable), 0);
- end;
- end;
- end;
-
- New (CtxTbl);
- if Mode = stCreate then begin
- CtxTbl^. N := 0;
- end;
-
- IdxTbl. Init (MaxCollectionSize, 0);
- IdxTbl. Duplicates := True;
- end;
-
- destructor THelpFile.Done;
- var I: Integer;
- R: TRecHdr;
- TmpW: Word;
- StartPos,
- EndPos,
- CtxStart: Longint;
- CC: TCharCounter;
- begin
- System. Write ('building compression record... '#13);
- FillChar (CC, SizeOf (CC), 0);
- for I := 0 to IdxTbl.Count - 1 do
- PIndexEntry (IdxTbl. At (I))^.Topic^.UpdateCharCounter (CC);
- CharCounter2CompRec (CC, FileStart. CompRec);
- WriteLn ('building compression record... done');
-
- Write (FileStart, SizeOf (FileStart));
-
- CtxTbl^. N := IdxTbl. Count + 1;
- CtxTbl^. T [0] := $FFFFFFFF;
-
- R. RecType := RT_Context;
- R. RecLength := 2 + CtxTbl^. N * 3;
- Write (R, SizeOf (R));
- Write (CtxTbl^. N, SizeOf (CtxTbl^. N));
- CtxStart := GetPos;
- if CtxTbl^. N > 0 then
- for I := 0 to CtxTbl^. N - 1 do
- Write (CtxTbl^.T [I], 3);
-
- IdxTbl. SetCtxs;
-
- I := 31;
- repeat
- StartPos := GetPos;
- R. RecType := RT_Index;
- R. RecLength := 0;
- Write (R, SizeOf (R));
- TmpW := IdxTbl. RealCount;
- Write (TmpW, 2);
- IdxTbl. Write (Self);
- EndPos := GetPos;
- WriteLn ('index size - ', EndPos - StartPos - SizeOf (R));
- Seek (StartPos);
- if EndPos - StartPos - SizeOf (R) >= 65536 then begin
- Dec (I);
- WriteLn ('rebuilding index - level ', I);
- IdxTbl. ReBuild (I);
- end;
- until EndPos - StartPos - SizeOf (R) < 65536;
- R. RecLength := EndPos - StartPos - SizeOf (R);
- Write (R, SizeOf (R));
- Seek (EndPos);
-
- StartPos := GetPos;
- R. RecType := RT_ScreenTags;
- R. RecLength := 0;
- Write (R, SizeOf (R));
- IdxTbl. AltWrite (Self, 'Interrupt List');
- EndPos := GetPos;
- WriteLn ('alternative index size - ', EndPos - StartPos - SizeOf (R));
- Seek (StartPos);
- if EndPos - StartPos - SizeOf (R) >= 65536 then begin
- WriteLn ('alternative index is too large.');
- Halt (1);
- end;
- R. RecLength := EndPos - StartPos - SizeOf (R);
- Write (R, SizeOf (R));
- Seek (EndPos);
-
- for I := 0 to IdxTbl.Count - 1 do begin
- CtxTbl^. T [PIndexEntry (IdxTbl. At (I))^.Ctx] := GetPos;
- PIndexEntry (IdxTbl. At (I))^.Topic^.Write (Self, FileStart. CompRec);
-
- PIndexEntry (IdxTbl. At (I))^.Topic^.WriteKeywords (Self, IdxTbl);
-
- System. Write (I, #13);
- end;
-
- Seek (CtxStart);
- if CtxTbl^. N > 0 then
- for I := 0 to CtxTbl^. N - 1 do
- Write (CtxTbl^.T [I], 3);
-
- IdxTbl. Done;
- if CtxTbl <> nil then
- Dispose (CtxTbl);
- inherited Done;
- end;
-
- end.
-